package org.news.web.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.system.domain.SysOss;
import org.dromara.system.mapper.SysOssMapper;
import org.news.web.domain.News;
import org.news.web.domain.Users;
import org.news.web.domain.vo.UsersVo;
import org.news.web.mapper.NewsMapper;
import org.news.web.mapper.UsersMapper;
import org.news.web.redis.RedisConstant;
import org.news.web.utils.DFAutils;
import org.springframework.stereotype.Service;
import org.news.web.domain.bo.CommentsBo;
import org.news.web.domain.vo.CommentsVo;
import org.news.web.domain.Comments;
import org.news.web.mapper.CommentsMapper;
import org.news.web.service.ICommentsService;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 评论Service业务层处理
 *
 * @author Gu Ci
 * @date 2024-04-03
 */
@Transactional
@RequiredArgsConstructor
@Service
public class CommentsServiceImpl implements ICommentsService {

    private final CommentsMapper baseMapper;

    private final UsersMapper usersMapper;


    private final NewsMapper newsMapper;

    private final SysOssMapper sysOssMapper;

    /**
     * 查询评论
     */
    @Override
    public CommentsVo queryById(Long commentId){
        return baseMapper.selectVoById(commentId);
    }

    /**
     * 查询评论列表
     */
    @Override
    public TableDataInfo<CommentsVo> queryPageList(CommentsBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Comments> lqw = buildQueryWrapper(bo);
        Page<CommentsVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

        if(ObjectUtil.isNotNull(result.getRecords()) && result.getRecords().size() >0){
            Set<Long> collect = result.getRecords().stream().map(item -> {
                return item.getUserId();
            }).collect(Collectors.toSet());

            List<Users> users = usersMapper.selectList(new LambdaQueryWrapper<Users>().in(Users::getUserId, collect));
            users.forEach(user ->{
                result.getRecords().stream().forEach(item ->{
                    if(item.getUserId() == user.getUserId()){
                        item.setUsername(user.getUsername());
                    }
                });
            });
        }
        /**
         * 获取新闻标题
         */
        if(ObjectUtil.isNotNull(result.getRecords()) && result.getRecords().size() >0){
            Set<Long> collect = result.getRecords().stream().map(item -> {
                return item.getNewsId();
            }).collect(Collectors.toSet());
            List<News> news = newsMapper.selectList(new LambdaQueryWrapper<News>().in(News::getNewsId, collect));

            news.stream().forEach(New->{
                result.getRecords().forEach(item ->{
                    if(New.getNewsId() == item.getNewsId()){
                        item.setTitle(New.getTitle());
                    }
                });
            });
        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询评论列表
     */
    @Override
    public List<CommentsVo> queryList(CommentsBo bo) {
        LambdaQueryWrapper<Comments> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Comments> buildQueryWrapper(CommentsBo bo) {
        LambdaQueryWrapper<Comments> lqw = Wrappers.lambdaQuery();
        Set<Long> userIds = null;
        if(StringUtils.isNotBlank(bo.getUsername())){
            List<Users> username = usersMapper.selectList(new QueryWrapper<Users>().like("username", bo.getUsername()));
            if(ObjectUtil.isNotNull(username) && username.size() >0){
                userIds = username.stream().map(Users::getUserId).collect(Collectors.toSet());
            }else{
//                查询不到用户 给一个查不到的id
                userIds = new HashSet<>();
                userIds.add(-1l);
            }
        }
        lqw.in(userIds!= null, Comments::getUserId, userIds);
        return lqw;
    }

    /**
     * 新增评论
     */
    @Override
    public Boolean insertByBo(CommentsBo bo) {
        Comments add = MapstructUtils.convert(bo, Comments.class);
        validEntityBeforeSave(add);
        DFInsert(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setCommentId(add.getCommentId());
        }
//      添加用户行为数据
        RedisUtils.addCacheSet(RedisConstant.XIN_WEI + ":" + bo.getUserId(),bo.getNewsId());
        RedisUtils.setCacheMapValue(RedisConstant.XIN_WEI + ":" + bo.getUserId() + ":" + bo.getNewsId(),RedisConstant.IS_COMM,1);
//      修改新闻表中对应的新闻数量
        int update = newsMapper.update(new LambdaUpdateWrapper<News>().eq(News::getNewsId, bo.getNewsId()).setSql("comments=comments+1"));
        return flag;
    }

    /**
     * 输入默认值
     * @param add
     */
    private void DFInsert(Comments add) {
        // 设置评论父节点默认值
        if(ObjectUtil.isNotNull(add) && add.getCommentId() == null && add.getParentCommentId() == null){
            add.setParentCommentId(-1l);
        }
    }

    /**
     * 修改评论
     */
    @Override
    public Boolean updateByBo(CommentsBo bo) {
        Comments update = MapstructUtils.convert(bo, Comments.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 判断评论是否有敏感词
     */
    private void validEntityBeforeSave(Comments entity){
        //判断评论是否有敏感词
        Map<String, Integer> map = DFAutils.matchWords(entity.getContent());
        if(map.size() >0){
            StringBuilder words = new StringBuilder();
            map.entrySet().stream().forEach(item ->{
                words.append(item.getKey());
                words.append(",");
            });
            System.out.println("违规词："+words.toString());
            throw new ServiceException("存在违规词："+words+"创建失败");
        }
    }

    /**
     * 批量删除评论
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {


        HashSet<Long> delIds = new HashSet<>();
//        查询这些评论相关评论新闻的评论信息
        List<CommentsVo> commentsVos = baseMapper.selectVoList(new LambdaQueryWrapper<Comments>().in(Comments::getCommentId, ids));
        Set<Long> collect = commentsVos.stream().map(item -> {
            return item.getNewsId();
        }).collect(Collectors.toSet());

        List<CommentsVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<Comments>().in(Comments::getNewsId, collect));
//        删除相关评论信息存储
        ArrayList<CommentsVo> delInfo = new ArrayList<>();
        ids.forEach(id ->{
            list.forEach( item ->{
                if(id == item.getCommentId()){
                    delInfo.add(item);
                }
            });
        });
        AtomicInteger begin = new AtomicInteger();
        AtomicInteger end = new AtomicInteger();
        AtomicInteger i = new AtomicInteger(0);
        ids.forEach(id ->{
            begin.set(delIds.size());
            getComIds(id,delIds,list);
            end.set(delIds.size());
//          删除相关评论数量
            newsMapper.update(new LambdaUpdateWrapper<News>().eq(News::getNewsId,delInfo.get(i.intValue()).getNewsId()).setSql("comments=comments-"+(end.intValue()-begin.intValue())));
            i.incrementAndGet();
        });
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(delIds) > 0;
    }
    /**
     * 获取当前评论信息的所有子评论 id
     */
    public void getComIds(Long id,Set<Long> cIds,List<CommentsVo> list){
        cIds.add(id);
        for(int i=0;i<list.size();i++){
            if(id.longValue() == list.get(i).getParentCommentId().longValue()){
                getComIds(list.get(i).getCommentId(),cIds,list);
            }
        }
    }
    /**
     * 获取评论信息
     * @param id
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<CommentsVo> getNewsCommentPage(Integer id, PageQuery pageQuery) {
//        查询10条评论时间最早的顶级评论
        Page<CommentsVo> result = baseMapper.selectVoPage(pageQuery.build(), new LambdaQueryWrapper<Comments>().eq(Comments::getParentCommentId,-1).eq(Comments::getNewsId,id).orderByAsc(Comments::getCreationTime));
        if(result.getRecords().size() == 0){
            throw new ServiceException("没有评论");
        }
        setUserInfo(result.getRecords());
        //        获取当前新闻的所有评论
        List<CommentsVo> commentsVos = baseMapper.selectVoList(new LambdaQueryWrapper<Comments>().eq(Comments::getNewsId, id).orderByAsc(Comments::getCreationTime));
        setUserInfo(commentsVos);
//        获取评论逻辑   获取评论时间最早的子节点
        result.getRecords().forEach(
            item->{
                item.setChildComment(new ArrayList<>());
                dfsSetValue(0,item,item.getChildComment(),commentsVos);
            }
        );
        return TableDataInfo.build(result);
    }

    // 补充用户信息
    private void setUserInfo(List<CommentsVo> records) {
//        获取所有用户信息
        Set<Long> collect = records.stream().map(commentsVo -> {
            return commentsVo.getUserId();
        }).collect(Collectors.toSet());
        List<UsersVo> usersVos = usersMapper.selectVoList(new LambdaQueryWrapper<Users>().in(Users::getUserId, collect));
//        获取所有图片id信息
        Set<Long> collect1 = usersVos.stream().map(usersVo -> {
            return Long.valueOf(usersVo.getProfilePicture());
        }).collect(Collectors.toSet());
        List<SysOss> sysOsses = sysOssMapper.selectList(new LambdaQueryWrapper<SysOss>().in(SysOss::getOssId, collect1));
//        把用户中的图片进行赋值
        usersVos.forEach(usersVo -> {
            sysOsses.forEach(sysOss -> {
                if(Long.valueOf(usersVo.getProfilePicture()).longValue()  == sysOss.getOssId().longValue()){
                    usersVo.setPictureUrl(sysOss.getUrl());
                }
            });
        });
//        把评论的用户信息进行赋值
        records.forEach( record ->{
            usersVos.forEach( usersVo -> {
                if (record.getUserId() == usersVo.getUserId()) {
                    record.setUsername(usersVo.getUsername());
                    record.setPictureUrl(usersVo.getPictureUrl());
                }
            });
        });
    }
    //    深度时间优先赋值
    //    扁平化评论 处理为主要评论 和 次要评论
    public void dfsSetValue(int begin,CommentsVo root,List<CommentsVo> local,List<CommentsVo> list){
//            开辟空间
            for(int j=0;j<list.size();j++){
                if(root.getCommentId() == list.get(j).getParentCommentId()){
//                    证明是父子关系 加入进去
                    list.get(j).setToUserName(root.getUsername());
                    local.add(list.get(j));
//                    进行深度递归
                    dfsSetValue(local.size()-1,local.get(local.size()-1),local,list);
                }
            }

    }


    /**
     * 删除评论和他的子评论
     */

}
